﻿using System;
using System.Collections;
using System.Linq;
using System.Runtime.InteropServices;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.Model;

namespace UtilZ.Dotnet.Ex.DataStruct
{
#pragma warning disable 8500

    /// <summary>
    /// 扩展数组类
    /// </summary>
    unsafe public class ArrayZ<T> : ICollection, IEnumerable
        where T : struct
    {
        private readonly bool _fixCapcity = false;

        private readonly T* _ptr = null;
        /// <summary>
        /// 获取数据指针
        /// </summary>
        public T* Ptr
        {
            get { return this._ptr; }
        }

        private T[] _values = null;
        /// <summary>
        /// 获取数组
        /// </summary>
        public T[] Values
        {
            get { return this._values; }
        }

        /// <summary>
        /// 获取数组容量
        /// </summary>
        public int Capcity
        {
            get
            {
                var values = this._values;
                if (values == null)
                {
                    return 0;
                }
                else
                {
                    return values.Length;
                }
            }
        }

        /// <summary>
        /// 索引获取或设置值
        /// </summary>
        /// <param name="index">索引</param>
        /// <returns>指定索引处的值</returns>
        /// <exception cref="ArgumentOutOfRangeException">索引超出范围</exception>
        public T this[int index]
        {
            get
            {
                //if (this._startIndex == 0 && (this._values == null || index < 0 || index >= this._length))
                //{
                //    throw new ArgumentOutOfRangeException();
                //}
                //else
                //{
                //    if (this._values == null || index < 0)
                //    {
                //        throw new ArgumentOutOfRangeException();
                //    }

                //    index = this._startIndex + index;
                //    if (index >= this._length)
                //    {
                //        throw new ArgumentOutOfRangeException();
                //    }
                //}

                if (this._ptr == null)
                {
                    return this._values[this._startIndex + index];
                }
                else
                {
                    return this._ptr[index];
                }
            }
            set
            {
                //if (this._startIndex == 0 && (this._values == null || index < 0 || index >= this._length))
                //{
                //    throw new ArgumentOutOfRangeException();
                //}
                //else
                //{
                //    if (this._values == null || index < 0)
                //    {
                //        throw new ArgumentOutOfRangeException();
                //    }

                //    index = this._startIndex + index;
                //    if (index >= this._length)
                //    {
                //        throw new ArgumentOutOfRangeException();
                //    }
                //}

                if (this._ptr == null)
                {
                    this._values[index] = value;
                }
                else
                {
                    this._ptr[index] = value;
                }
            }
        }

        /// <summary>
        /// 标记数据
        /// </summary>
        public object Tag { get; set; }

        private Exception _exception = null;
        /// <summary>
        /// 检查容量是足够,返回检查结果[true:表示扩展容量成功;false:表示扩展容量失败].
        /// 当容量足够或扩展容量成功时,调整数据长度为检查容量的长度.
        /// </summary>
        /// <param name="capcity">新的容量,当大于旧的容量是扩展容量</param>
        /// <returns></returns>
        public bool Check(int capcity)
        {
            this._exception = null;
            if (this._values != null && capcity <= this._values.Length)
            {
                this._startIndex = 0;
                this._length = capcity;
                return true;
            }

            if (this._fixCapcity)
            {
                this._exception = new InvalidOperationException("数组容量大小已固定,不允许扩展");
                return false;
            }

            if (capcity < 0 || capcity > ArrayEx.MaxLength)
            {
                this._exception = new ArgumentOutOfRangeException("数组容量超出范围");
                return false;
            }

            T[] values;
            try
            {
                values = new T[capcity];
                if (this._values != null)
                {
                    Array.Copy(this._values, 0, values, 0, this._length);
                }
            }
            catch (Exception ex)
            {
                this._exception = ex;
                return false;
            }

            this._values = values;
            this._startIndex = 0;
            this._length = capcity;
            return true;
        }


        /// <summary>
        /// 抛出内存调失败异常
        /// </summary>
        public void ThrowAdjustFailException()
        {
            var exception = this._exception;
            if (exception != null)
            {
                throw exception;
            }
        }

        /// <summary>
        /// 设置数据长度
        /// </summary>
        /// <param name="startIndex">起始位置</param>
        /// <param name="length">数据长度</param>
        /// <exception cref="ArgumentOutOfRangeException">长度越界异常</exception>
        public void SetLength(int startIndex, int length)
        {
            if (this._values == null)
            {
                throw new ArgumentOutOfRangeException("未检查数组容量");
            }

            if (startIndex < 0 || startIndex >= this._values.Length)
            {
                throw new ArgumentOutOfRangeException("设置数据起始位置超出范围");
            }

            if (length < 0 || startIndex + length > this._values.Length)
            {
                throw new ArgumentOutOfRangeException("设置数据长度超出范围");
            }

            this._startIndex = startIndex;
            this._length = length;
        }

        /// <summary>
        /// 获取ArraySegment
        /// </summary>
        /// <returns>ArraySegment</returns>
        public ArraySegment<T> GetArraySegment()
        {
            return new ArraySegment<T>(this._values, this._startIndex, this._length);
        }

        /// <summary>
        /// 获取Span
        /// </summary>
        /// <returns>ArraySegment</returns>
        public Span<T> GetSpan()
        {
            if (this._ptr == null)
            {
                return new Span<T>(this._values, this._startIndex, this._length);
            }
            else
            {
                return new Span<T>(this._ptr, this._length);
            }
        }

        /// <summary>
        /// 获取Span
        /// </summary>
        /// <returns>SpanZ</returns>
        public SpanZ<T> GetSpanZ()
        {
            return new SpanZ<T>(this._ptr, this._length);
        }


        /// <summary>
        /// 构造函数
        /// </summary>
        public ArrayZ()
        {
            this._values = Array.Empty<T>();
            this._fixCapcity = false;
            this._startIndex = -1;
            this._length = 0;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="capcity">初始化容量</param>
        /// <param name="fixCapcity">是否固定数组容量[true:可调用Check方法扩展容量;false:固定容量,不可扩展]</param>
        public ArrayZ(int capcity, bool fixCapcity = false)
        {
            if (capcity <= 0 || capcity > ArrayEx.MaxLength)
            {
                throw new ArgumentOutOfRangeException("数组容量超出范围");
            }

            this._values = new T[capcity];
            this._startIndex = 0;
            this._length = capcity;
            this._fixCapcity = fixCapcity;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="values"></param>
        /// <param name="fixCapcity">是否固定数组容量[true:可调用Check方法扩展容量;false:固定容量,不可扩展]</param>
        public ArrayZ(T[] values, bool fixCapcity = false)
        {
            if (values == null || values.Length == 0)
            {
                throw new ArgumentNullException(nameof(values));
            }

            this._values = values;
            this._startIndex = 0;
            this._length = values.Length;
            this._fixCapcity = fixCapcity;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="values"></param>
        /// <param name="fixCapcity">是否固定数组容量[true:可调用Check方法扩展容量;false:固定容量,不可扩展]</param>
        public ArrayZ(ArraySegment<T> values, bool fixCapcity = false)
        {
            this._values = values.Array;
            this._startIndex = values.Offset;
            this._length = values.Count;
            this._fixCapcity = fixCapcity;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="ptr">初始指针</param>
        /// <param name="length">指针数据长度</param>
        public ArrayZ(T* ptr, int length)
        {
            if (ptr == null)
            {
                throw new ArgumentNullException(nameof(ptr));
            }

            this._values = null;
            this._ptr = ptr;
            this._startIndex = 0;
            this._length = length;
            this._fixCapcity = true;
        }




        private int _startIndex = -1;
        /// <summary>
        /// 数据起始位置
        /// </summary>
        public int StartIndex
        {
            get { return this._startIndex; }
        }

        /// <summary>
        /// 有效数据元素个数
        /// </summary>
        private int _length = 0;
        /// <summary>
        /// 有效数据元素个数
        /// </summary>
        public int Length
        {
            get { return this._length; }
        }

        /// <summary>
        /// 获取可用数据元素个数
        /// </summary>
        int ICollection.Count
        {
            get { return this._length; }
        }

        /// <summary>
        /// 是否支持同步
        /// </summary>
        public bool IsSynchronized
        {
            get { return false; }
        }

        private readonly object _syncRoot = new object();
        /// <summary>
        /// 获取同步对象
        /// </summary>
        public object SyncRoot
        {
            get { return _syncRoot; }
        }

        /// <summary>
        /// 复制当前集合数据到目标数组
        /// </summary>
        /// <param name="array"></param>
        /// <param name="index"></param>
        public void CopyTo(Array array, int index)
        {
            if (this._ptr == null)
            {
                if (index < 0 || index + this._length > array.Length)
                {
                    throw new ArgumentOutOfRangeException(nameof(index));
                }

                Array.Copy(this._values, this._startIndex, array, index, this._length);
            }
            else
            {
                for (int i = 0; i < this._length; i++)
                {
                    array.SetValue(this._ptr[i], index + i);
                }
            }
        }

        /// <summary>
        /// ToArrayEx
        /// </summary>
        /// <returns>新的数组集合</returns>
        public ArrayZ<T> ToArrayEx()
        {
            if (this._ptr == null)
            {
                var values = this._values;
                if (values == null)
                {
                    return new ArrayZ<T>();
                }
                else
                {
                    return new ArrayZ<T>(values.ToArray());
                }
            }
            else
            {
                return new ArrayZ<T>(this._ptr, this._length);
            }
        }

        /// <summary>
        /// ToArray
        /// </summary>
        /// <returns>新的数组集合</returns>
        public T[] ToArray()
        {
            if (this._ptr == null)
            {
                if (this._values == null)
                {
                    return null;
                }
                else
                {
                    T[] buffer = new T[this._length];
                    Array.Copy(this._values, this._startIndex, buffer, 0, this._length);
                    return buffer;
                }
            }
            else
            {
                T[] arr = new T[this._length];
                fixed (T* arrPTr = arr)
                {
                    NativeMemory.Copy(this._ptr, arrPTr, new nuint((ulong)(this._length * sizeof(T))));
                }

                return arr;
            }
        }

        /// <summary>
        /// 获取枚举器
        /// </summary>
        /// <returns>枚举器</returns>
        public IEnumerator GetEnumerator()
        {
            if (this._ptr == null)
            {
                return new PartEnumerator<T>(this._values, this._startIndex, this._length);
            }
            else
            {
                return new PointerEnumerator<T>(this._ptr, this._length);
            }
        }

    }

}
